package common

import (
	"context"
	"encoding/json"

	"github.com/gorhill/cronexpr"
	"strings"
	"time"
)

//定时任务
type Job struct {
	Name        string `json:"name"`
	Command     string `json:"command"`
	CronExpr    string `json:"cronExpr"` //表达式
	Description string `json:"description"`
}

//任务调度任务
type JobScheduleTask struct {
	Job      *Job
	Expr     *cronexpr.Expression //解析好的cronexp表达式
	NextTime time.Time
}

//任务执行状态
type JobExecuteInfo struct {
	Job        *Job
	PlanTime   time.Time          //理论上的调度时间
	RealTime   time.Time          //真实的调度时间
	CancelFunc context.CancelFunc //用于取消上下文，配对使用
	Cancel     context.Context
}

//任务执行结果
type JobExecutorResult struct {
	Executor  *JobExecuteInfo //执行状态
	Ouput     []byte
	Err       error
	StartTime time.Time //真是启动时间
	EndTime   time.Time //结束时间

}

//两类事件：1.删除任务;2.更新任务
type JobEvent struct {
	EventType int //SAVE和DELETE
	Job       *Job
}

//响应结果值
type Response struct {
	Errno int         `json:"errno"`
	Msg   string      `json:"msg"`
	Data  interface{} `json:"data"`
}

//用于分页用的
type JobList struct {
	JobList     []*Job `json:"jobList"`
	JobTotalNum int    `json:"jobTotalNum"`
}

//用于日志存储的
type JobLog struct {
	JobName      string `json:"jobName" bson:"jobName"`           //任务名称
	Command      string `json:"command" bson:"command"`           //命令
	Err          string `json:"err" bson:"err"`                   //错误信息
	Output       string `json:"output" bson:"output"`             //脚本输出
	PlanTime     int64  `json:"planTime" bson:"planTime"`         //计划开始时间
	ScheduleTime int64  `json:"scheduleTime" bson:"scheduleTime"` //实际调度时间，两者相差太多，表示压力太大
	StartTime    int64  `json:"startTime" bson:"startTime"`       //开始时间
	EndTime      int64  `json:"endTime" bson:"endTime"`           //结束时间，计算出任务执行时间
	Author       string `json:"author"  bson:"author"`
}

//批量写入日志
type LogBatch struct {
	LogItems []interface{}
}

//查询条件
type LogFilter struct {
	JobName string `bson:"jobName"`
}

//排序规则条件
type LogSortRule struct {
	StartTime int `bson:"startTime"`
}

//日志补偿，以kafka为例
type KafkaBackOff struct {
	KafkaAcks        int
	KafkaTopics      string
	KafkaPartitioner int
	KafkaTimeout     int
	KafkaBrokers     string
}

func BuildJobEvent(eventType int, job *Job) *JobEvent {
	return &JobEvent{
		EventType: eventType,
		Job:       job,
	}
}

func BuildResponse(errno int, msg string, data interface{}) (resp []byte, err error) {
	var (
		response Response
	)
	response.Errno = errno
	response.Msg = msg
	response.Data = data
	resp, err = json.Marshal(response)
	return resp, nil
}

//反序列化
func UnPackJson(value []byte) (ret *Job, err error) {
	var (
		job *Job
	)
	job = &Job{}
	if err = json.Unmarshal(value, job); err != nil {
		return
	}
	ret = job
	return
}

//提取任务名,/cron/jobs/job10---->去掉/cron/jobs/,只剩下job10
func ExtractJobName(jobPath, prefix string) string {
	return strings.TrimPrefix(jobPath, prefix)
}

//构造执行计划
func BuildSchedulerTask(job *Job) (jobScheduler *JobScheduleTask, err error) {
	var (
		expr *cronexpr.Expression
	)

	if expr, err = cronexpr.Parse(job.CronExpr); err != nil {
		return
	}
	jobScheduler = &JobScheduleTask{
		Job:      job,
		Expr:     expr,
		NextTime: expr.Next(time.Now()), //算出下一次执行时间
	}
	return
}

//构建任务执行信息
func BuildSchedulerInfo(task *JobScheduleTask) (jobExcuteInfo *JobExecuteInfo) {
	jobExcuteInfo = &JobExecuteInfo{
		Job:      task.Job,
		PlanTime: task.NextTime, //可以通过比较这两个值，来计算是否有延迟
		RealTime: time.Now(),    //当前真实调度时间
	}
	jobExcuteInfo.Cancel, jobExcuteInfo.CancelFunc = context.WithCancel(context.TODO())
	return
}
